/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package opensocial.apps.friendforsale.command;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import opensocial.apps.common.Message;
import opensocial.apps.friendforsale.Tools;
import opensocial.apps.friendforsale.model.Activity;
import opensocial.apps.friendforsale.model.ActivityType;
import opensocial.apps.friendforsale.model.Player;

import org.apache.log4j.Logger;

/**
 * buy slave accept request slaveid=xxx&nickname=xxx
 * @author Sirius
 * 
 */
public class BuyCommand extends FriendsaleBaseCommand {
  private static final Logger LOGGER = Logger.getLogger(BuyCommand.class);

  private String master;
  private String slave;

  @Override
  public boolean execute() throws Exception {
    String slaveId = request.getParameter("slaveid");
    String nickname = request.getParameter("nickname");

    if (slaveId == null) {
      output(new Message(MessageId.PARAM_ERROR, null));
      LOGGER.error("parameter error:slave id is null");
      return END;
    }

    if (nickname != null && nickname.length() > 20) {
      nickname = nickname.substring(0, 20);
      LOGGER.info("nickname too long,trim to 20 char");
    }

    Player viewer = this.getViewer();
    Player slave = this.getPlayer(slaveId);

    if (slave == null) {
      output(new Message(MessageId.PARAM_ERROR, null));
      LOGGER.error("parameter error:slave " + slaveId + " not found");
      return END;
    }

    // check if already has this slave
    if (Tools.isSlave(viewer, slave)) {
      output(new Message(MessageId.ALREADY_HAVE_SLAVE, null));
      LOGGER.info("parameter error: viewer: " + vid + " already have slave");
      return END;
    }
    if (Tools.isSlave(slave, viewer)) {
      output(new Message(MessageId.CANT_BUY_MASTER, null));
      LOGGER.info("parameter error: viewer: " + vid + " can`t buy master.");
      return END;
    }

    int slaveprice = slave.getPrice();
    int cash = viewer.getCash();
    if (cash < slaveprice) {
      output(new Message(MessageId.NOT_ENOUGH_MONEY, null));
      LOGGER.info("viewer: " + vid + " not enough money.");
      return END;
    }

    Map<String, Object> params = new HashMap<String, Object>();

    // check if slave is working.
    Activity lastAI = persist.getLastActivity(null, slave, ActivityType.FIX);

    if (lastAI != null) {
      Date buyuntil = new Date(lastAI.getTime());
      Date now = new Date();
      if (now.before(buyuntil)) {
        params.put("slave", slave.getUserId());
        params.put("work", lastAI.getCommand());
        params.put("fixuntil", buyuntil);
        output(new Message(MessageId.SLAVE_AT_WORK, params));
        LOGGER.info("slave:" + slave.getUserId() + "is at work");
        return END;
      }
    }
    // TODO: check buy limit per day
    // all check pass
    this.hasError(false);

    cash = cash - slaveprice;
    viewer.setCash(cash);
    viewer.setSlavenum(viewer.getSlavenum() + 1);

    Tools.Profit profit;
    if (slave.getMasterid() != null) {
      profit = Tools.count(slaveprice, true);
      Player orgnMaster = this.getPlayer(slave.getMasterid());
      orgnMaster.setCash(orgnMaster.getCash() + slaveprice
          + profit.getOldMaster());
      orgnMaster.setCapital(orgnMaster.getCapital() + profit.getOldMaster());
      orgnMaster.setSlavenum(orgnMaster.getSlavenum() - 1);
      params.put("oldmaster", orgnMaster);

      Activity act = new Activity();
      act.setTime(new Date().getTime());
      act.setContainer(viewer.getContainer());
      act.setCommand(MessageId.BUY_FROM_YOU);
      act.setActor(slave.getUserId());
      act.setActorName(slave.getName());
      act.setTarget(orgnMaster.getUserId());
      act.setTargetName(orgnMaster.getName());
      act.setType(ActivityType.BUY);
      // record origin price and profit
      act.setArgs(slaveprice, profit.getOldMaster());

      persist.save(orgnMaster);
      persist.save(act);

      LOGGER.info("save oldmaster:" + orgnMaster.getUserId());
    } else {
      profit = Tools.count(slave.getPrice(), false);
    }

    slave.setPrice(profit.getNewPrice());
    slave.setCash(slave.getCash() + profit.getSlave());
    slave.setCapital(slave.getCapital() + profit.getSlave());
    slave.setMasterid(viewer.getUserId());
    slave.setMastername(viewer.getName());
    slave.setNickname(nickname);
    params.put("profit", profit.getSlave());

    params.put("viewer", viewer);
    params.put("slave", slave);
    
    Activity ai = new Activity();
    ai.setTime(new Date().getTime());
    ai.setContainer(viewer.getContainer());
    ai.setActor(viewer.getUserId());
    ai.setActorName(viewer.getName());
    ai.setTarget(slave.getUserId());
    ai.setTargetName(slave.getName());
    ai.setCommand(MessageId.BUY);
    ai.setType(ActivityType.BUY);
    ai.setArgs(slaveprice);

    persist.save(ai);
    persist.save(slave);
    persist.save(viewer);

    LOGGER.info("buy slave successful");
    output(new Message(MessageId.BUY, params));

    return false;
  }

  public String getMaster() {
    return master;
  }

  public void setMaster(String master) {
    this.master = master;
  }

  public String getSlave() {
    return slave;
  }

  public void setSlave(String slave) {
    this.slave = slave;
  }

}
